package controllers

import (
	"context"
	"fmt"
	"net/http"
	"path/filepath"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/inntu/backend/utils"
)

// UploadController 文件上传控制器
type UploadController struct {
	cosClient *utils.COSClient
}

// NewUploadController 创建上传控制器实例
func NewUploadController() *UploadController {
	// 创建COS客户端，使用zyx配置
	cosClient, err := utils.NewCOSClient("zyx")
	if err != nil {
		// 如果创建失败，记录错误但不阻止控制器创建
		fmt.Printf("创建COS客户端失败: %v\n", err)
	}

	return &UploadController{
		cosClient: cosClient,
	}
}

// UploadFileResponse 文件上传响应结构
type UploadFileResponse struct {
	URL      string `json:"url"`      // 文件访问URL
	Filename string `json:"filename"` // 文件名
	Size     int64  `json:"size"`     // 文件大小
	Type     string `json:"type"`     // 文件类型
}

// UploadFile 上传文件到腾讯COS并返回URL
// @Summary 上传文件
// @Description 上传文件到腾讯云COS并返回访问URL
// @Tags 文件上传
// @Accept multipart/form-data
// @Produce json
// @Param file formData file true "要上传的文件"
// @Param folder formData string false "存储文件夹（可选，默认为uploads）"
// @Success 200 {object} utils.Response{data=UploadFileResponse}
// @Failure 400 {object} utils.Response
// @Failure 500 {object} utils.Response
// @Router /api/v1/upload [post]
func (c *UploadController) UploadFile(ctx *gin.Context) {
	// 检查COS客户端是否可用
	if c.cosClient == nil {
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "文件上传服务不可用")
		return
	}

	// 获取上传的文件
	file, header, err := ctx.Request.FormFile("file")
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "获取上传文件失败: "+err.Error())
		return
	}
	defer file.Close()

	// 获取文件夹参数（可选）
	folder := ctx.DefaultPostForm("folder", "uploads")

	// 验证文件大小（限制为10MB）
	const maxFileSize = 10 << 20 // 10MB
	if header.Size > maxFileSize {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "文件大小不能超过10MB")
		return
	}

	// 获取文件扩展名
	ext := strings.ToLower(filepath.Ext(header.Filename))

	// 根据文件扩展名确定Content-Type
	var fileContentType string
	switch ext {
	// 图片文件
	case ".png":
		fileContentType = "image/png"
	case ".jpg", ".jpeg":
		fileContentType = "image/jpeg"
	case ".gif":
		fileContentType = "image/gif"
	case ".svg":
		fileContentType = "image/svg+xml"
	case ".webp":
		fileContentType = "image/webp"
	// 文档文件
	case ".pdf":
		fileContentType = "application/pdf"
	case ".doc":
		fileContentType = "application/msword"
	case ".docx":
		fileContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
	case ".xls":
		fileContentType = "application/vnd.ms-excel"
	case ".xlsx":
		fileContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
	case ".ppt":
		fileContentType = "application/vnd.ms-powerpoint"
	case ".pptx":
		fileContentType = "application/vnd.openxmlformats-officedocument.presentationml.presentation"
	// 文本文件
	case ".txt":
		fileContentType = "text/plain"
	case ".md":
		fileContentType = "text/markdown"
	// 压缩文件
	case ".zip":
		fileContentType = "application/zip"
	case ".rar":
		fileContentType = "application/x-rar-compressed"
	// 音视频文件
	case ".mp3":
		fileContentType = "audio/mpeg"
	case ".mp4":
		fileContentType = "video/mp4"
	case ".avi":
		fileContentType = "video/x-msvideo"
	default:
		// 检查MIME类型
		detectedType := header.Header.Get("Content-Type")
		if detectedType != "" {
			fileContentType = detectedType
		} else {
			fileContentType = "application/octet-stream"
		}
	}

	// 生成唯一文件名
	newFilename := fmt.Sprintf("%d_%s", time.Now().Unix(), header.Filename)
	cosKey := fmt.Sprintf("%s/%s", folder, newFilename)

	// 设置上传选项
	uploadOpts := &utils.UploadOptions{
		ContentType: fileContentType,
		ACL:         "public-read", // 设置为公开读取
		Metadata: map[string]string{
			"original-filename": header.Filename,
			"upload-time":       time.Now().Format(time.RFC3339),
			"file-size":         fmt.Sprintf("%d", header.Size),
		},
	}

	// 上传文件到COS
	ctxWithTimeout, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	err = c.cosClient.PutObject(ctxWithTimeout, cosKey, file, uploadOpts)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "文件上传失败: "+err.Error())
		return
	}

	// 获取文件访问URL
	fileURL := c.cosClient.GetObjectURL(cosKey)

	// 构造响应数据
	response := UploadFileResponse{
		URL:      fileURL,
		Filename: newFilename,
		Size:     header.Size,
		Type:     fileContentType,
	}

	utils.SuccessResponse(ctx, "文件上传成功", response)
}

// UploadImage 专门用于图片上传的接口
// @Summary 上传图片
// @Description 上传图片文件到腾讯云COS并返回访问URL（仅支持图片格式）
// @Tags 文件上传
// @Accept multipart/form-data
// @Produce json
// @Param file formData file true "要上传的图片文件"
// @Success 200 {object} utils.Response{data=UploadFileResponse}
// @Failure 400 {object} utils.Response
// @Failure 500 {object} utils.Response
// @Router /api/v1/upload/image [post]
func (c *UploadController) UploadImage(ctx *gin.Context) {
	// 添加详细日志记录
	fmt.Printf("[UploadImage] 开始处理图片上传请求\n")
	fmt.Printf("[UploadImage] Content-Type: %s\n", ctx.GetHeader("Content-Type"))
	fmt.Printf("[UploadImage] Content-Length: %s\n", ctx.GetHeader("Content-Length"))
	
	// 检查COS客户端是否可用
	if c.cosClient == nil {
		fmt.Printf("[UploadImage] 错误: COS客户端不可用\n")
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "文件上传服务不可用")
		return
	}

	// 获取上传的文件，支持'file'和'image'两个字段名
	file, header, err := ctx.Request.FormFile("file")
	if err != nil {
		// 如果'file'字段不存在，尝试'image'字段
		file, header, err = ctx.Request.FormFile("image")
		if err != nil {
			fmt.Printf("[UploadImage] 错误: 获取上传文件失败 (尝试了'file'和'image'字段): %v\n", err)
			utils.ErrorResponse(ctx, http.StatusBadRequest, "获取上传文件失败，请确保使用'file'或'image'作为表单字段名: "+err.Error())
			return
		}
		fmt.Printf("[UploadImage] 使用'image'字段获取文件成功\n")
	} else {
		fmt.Printf("[UploadImage] 使用'file'字段获取文件成功\n")
	}
	fmt.Printf("[UploadImage] 文件信息: 名称=%s, 大小=%d bytes\n", header.Filename, header.Size)
	defer file.Close()

	// 验证文件大小（限制为5MB）
	const maxFileSize = 5 << 20 // 5MB
	if header.Size > maxFileSize {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "图片文件大小不能超过5MB")
		return
	}

	// 获取文件扩展名并验证是否为图片
	ext := strings.ToLower(filepath.Ext(header.Filename))
	var fileContentType string
	switch ext {
	case ".png":
		fileContentType = "image/png"
	case ".jpg", ".jpeg":
		fileContentType = "image/jpeg"
	case ".gif":
		fileContentType = "image/gif"
	case ".svg":
		fileContentType = "image/svg+xml"
	case ".webp":
		fileContentType = "image/webp"
	default:
		// 检查MIME类型
		detectedType := header.Header.Get("Content-Type")
		if strings.HasPrefix(detectedType, "image/") {
			fileContentType = detectedType
		} else {
			utils.ErrorResponse(ctx, http.StatusBadRequest, "不支持的文件类型，请上传图片文件（png, jpg, gif, svg, webp）")
			return
		}
	}

	// 生成唯一文件名
	newFilename := fmt.Sprintf("%d_%s", time.Now().Unix(), header.Filename)
	cosKey := fmt.Sprintf("images/%s", newFilename)

	// 设置上传选项
	uploadOpts := &utils.UploadOptions{
		ContentType: fileContentType,
		ACL:         "public-read", // 设置为公开读取
		Metadata: map[string]string{
			"original-filename": header.Filename,
			"upload-time":       time.Now().Format(time.RFC3339),
			"file-size":         fmt.Sprintf("%d", header.Size),
			"file-type":         "image",
		},
	}

	// 上传文件到COS
	ctxWithTimeout, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	err = c.cosClient.PutObject(ctxWithTimeout, cosKey, file, uploadOpts)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "图片上传失败: "+err.Error())
		return
	}

	// 获取文件访问URL
	fileURL := c.cosClient.GetObjectURL(cosKey)

	// 构造响应数据
	response := UploadFileResponse{
		URL:      fileURL,
		Filename: newFilename,
		Size:     header.Size,
		Type:     fileContentType,
	}

	utils.SuccessResponse(ctx, "图片上传成功", response)
}